import json
import re

from django import http
from django.contrib.auth import authenticate, login, logout
from django.core.paginator import Paginator
from django.shortcuts import render, redirect
from django.http import HttpResponseForbidden, JsonResponse
from django.utils.decorators import method_decorator
from django_redis import get_redis_connection
# Create your views here.
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin

from goods.models import SKU
from orders.models import OrderInfo
from users.models import User, Area, Address
from django.core.mail import send_mail
from django.conf import settings

from utils import meiduo_signature
from utils.myemail import generate_verify_email_url, decode_email_token


class RegisterView(View):
    def get(self, request):
        return render(request, 'register_vue.html', context={'error_name_message': 'xxxxxxx'})

    # 1, 定义方法 使用post 提交表单数据
    def post(self, request):
        # 1, 接收数据
        data = request.POST  # 字典
        # username,pwd,cpwd,mobile,msg_code,allow
        user_name = data.get('user_name')
        pwd = data.get('pwd')
        cpwd = data.get('cpwd')
        phone = data.get('phone')
        msg_code = data.get('msg_code')
        allow = data.get('allow', None)
        # 如果勾选了, allow的值 是 'on'
        # 如果不勾选, 就不传这个值

        # 2, 校验数据
        if not all([user_name, pwd, cpwd, phone, msg_code]):
            return HttpResponseForbidden('参数不全')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', user_name):
            return HttpResponseForbidden('用户名格式不正确')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return HttpResponseForbidden('密码格式不正确')

        if pwd != cpwd:
            return HttpResponseForbidden('两次密码不一致')

        if not re.match(r'^1[3456789]\d{9}$', phone):
            return HttpResponseForbidden('手机号格式不正确')

        # todo:这里需要验证短信验证码
        # 取redis中的sms_code
        # # 获取redis客户端
        redis_client = get_redis_connection('verify_code')
        redis_sms_code = redis_client.get(phone)

        if redis_sms_code:
            redis_sms_code = redis_sms_code.decode()

        if msg_code != redis_sms_code:
            return HttpResponseForbidden('短信验证码错误')

        if allow != 'on':  # 如果勾选了, allow的值 是 'on'
            return HttpResponseForbidden('请勾选用户协议')

        # 3, 处理业务
        try:
            # user = User.objects.create(
            #     username = user_name,
            #     mobile=phone,
            # )
            # user.set_password(pwd)

            user = User.objects.create_user(
                username=user_name,
                password=pwd,
                mobile=phone
            )
        except Exception as e:
            print(e)
            return HttpResponseForbidden('用户创建失败')

        # 4, 响应结果
        return redirect('/')


class CheckUsernameView(View):
    # 定义方法
    def get(self, request, username):
        # 1, 接收参数
        pass

        # 2, 校验参数
        pass

        # 3, 处理业务
        count = User.objects.filter(username=username).count()

        # 4, 返回响应
        res = {
            'count': count
        }
        return JsonResponse(res)
        pass


class MobileCountView(View):
    # 1, 定义方法,
    def get(self, request, mobile):
        # 1, 接收数据
        pass

        # 2, 校验数据
        pass

        # 3, 处理业务
        # 统计这个手机号的用户数量
        count = User.objects.filter(mobile=mobile).count()

        # 4, 返回响应
        res = {
            'code': 0,
            'errmsg': '请求成功',
            'count': count
        }
        return JsonResponse(res)
        pass


from django.core.cache import cache

from django.contrib.auth.decorators import login_required


class LoginView(View):
    def get(self, request):
        # 直接渲染返回login.html页面
        return render(request, 'login.html')

    def post(self, request):
        # 1, 接收数据
        username = request.POST.get('username')
        pwd = request.POST.get('pwd')
        remembered = request.POST.get('remembered')

        # 2, 校验数据
        if not all([username, pwd]):
            return HttpResponseForbidden('参数不全')

        # 3, 处理业务
        # 3,1 先根据用户名获取用户
        # try:
        #     User.objects.get(username=username)
        # except Exception as e:
        #     print(e)
        #     return HttpResponseForbidden('用户不存在')
        # 检查用户密码
        # user.check_password(raw_password=password)

        # 通过 authenticate() 方法 验证用户名和密码
        from django.contrib.auth import authenticate
        user = authenticate(request, username=username, password=pwd)

        if user:
            # 使用  django.contrib.auth.login  函数来登录用户
            login(request, user)
            print(user.username)

        else:
            print('密码错误')
            return HttpResponseForbidden('密码错误')
        # 4, 返回响应

        next = request.GET.get('next')
        if next == None:
            next = '/'

        response = redirect(next)

        if remembered != 'on':
            # 不用保存登录状态
            request.session.set_expiry(0)  # 关闭浏览器时 session失效
            response.set_cookie('username', user.username)
        else:
            # 需要保存用户登录状态
            request.session.set_expiry(None)  # 按照默认配置, (2周)
            response.set_cookie('username', user.username, expires=3600 * 24 * 14)

        return response

        pass


class LogoutView(View):
    def get(self, request):
        # 直接登出用户
        logout(request)

        response = redirect('/')
        # 通过响应对象, 向浏览器发送删除cookie的指令
        response.delete_cookie('username')

        return response


# class UserInfoView(View):
#     # def get(self, request):
#     #     # 展示用户中心页面
#     #     # 获取用户
#     #     user = request.user
#     #     print(user)
#     #     if user.is_authenticated:
#     #         # 登录了, 就显示用户中心页面
#     #         context = {
#     #             "mobile": '13312341234',
#     #             "email": '12345678@qq.com',
#     #             "email_active": True
#     #         }
#     #         return render(request, 'user_center_info.html', context=context)
#     #     else:
#     #         # user 是匿名用户 AnonymousUser
#     #         # 未登录就跳转去登录页面
#     #         return redirect('/login/')
#
#     @method_decorator(login_required)
#     def get(self, request):
#         # 展示用户中心页面
#         # 获取用户
#         user = request.user
#
#         context = {
#             "mobile": user.mobile,
#             "email": user.email,
#             "email_active": True
#         }
#         return render(request, 'user_center_info.html', context=context)

# 用户中心
class UserInfoView(LoginRequiredMixin, View):
    def get(self, request):
        # 展示用户中心页面

        user = request.user

        # 获取用户的历史浏览记录
        # 从redis 中获取,
        # 创建redis客户端
        redis_client = get_redis_connection('history')

        # lrange 获取 sku_id 的列表
        sku_ids = redis_client.lrange('history_%s' % user.id, 0, -1)

        # 遍历sku_id列表, 组装sku的信息
        sku_list = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            sku_data = {
                "id": sku.id,
                "image_url": sku.default_image_url.url,
                "name": sku.name,
                "price": sku.price
            }
            sku_list.append(sku_data)

        context = {
            "mobile": user.mobile,
            "email": user.email,
            "email_active": user.email_active,
            "sku_list": sku_list
        }
        return render(request, 'user_center_info.html', context=context)


# 发送邮件
class EmailSendView(LoginRequiredMixin, View):
    def put(self, request):
        # 1, 接收数据,  接收json数据  {email: "liangxuepeng@itcast.cn"}
        data = json.loads(request.body.decode())
        email = data.get('email')

        # 2, 校验数据
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 9999, 'errmsg': '邮箱格式有误'})

        # 3, 处理业务
        # 取用户
        user = request.user
        # 存邮箱
        user.email = email
        user.save()

        # 发邮件
        # +1 生成验证链接
        verity_email_url = generate_verify_email_url(user.id)

        # send_mail(subject='测试邮件', message=verity_email_url, from_email=settings.EMAIL_FROM,
        #           recipient_list=[user.email])

        from main import send_verify_email
        send_verify_email.delay('邮箱验证', verity_email_url, settings.EMAIL_FROM, user.email)

        # 4, 返回响应
        res = {
            'code': 0,
            'errmsg': '成功发送邮件'
        }
        return JsonResponse(res)

        pass


# 验证邮箱
# http://www.meiduo.site:8000/emails/verification/?token=eyJhbGciOiJIUzUxMiIsImlhdCI6MTU2OTU5MDAyNSwiZXhwIjoxNTY5NTkwMzI1fQ.eyJkYXRhIjoiYnVqaWEifQ.ggn0tKRJKnIZKjQ1WUoASRsJTXyQMhtLyvNsIivrQ6716zytp3sdyYtKDY3nIWXzF9Qt48I233Hl2gfTxfw4-A
class EmailActiveView(View):
    def get(self, request):
        # 验证邮件链接
        # 1, 接收数据
        token = request.GET.get('token')
        # 2, 校验数据
        if not token:
            return HttpResponseForbidden('token丢失')

        # 得到userid
        user_id = decode_email_token(token)

        if not user_id:
            return HttpResponseForbidden('token失效')

        # 3, 处理业务
        try:
            user = User.objects.get(id=user_id)
        except Exception as e:
            print(e)
            return HttpResponseForbidden('用户不存在')

        # 把用户邮箱激活
        user.email_active = True
        user.save()

        # 登录
        login(request, user)
        request.session.set_expiry(None)

        # 4, 返回响应
        # 重定向到用户中心
        response = redirect('/info/')
        response.set_cookie('username', user.username, expires=3600 * 24 * 14)

        return response
        pass


class AddressesView(LoginRequiredMixin, View):
    def get(self, request):
        # 获取收货地址页面
        # 1, 接收数据
        user = request.user

        # 2, 校验数据
        pass

        # 3, 处理业务
        # 取用户收货地址
        addresses = Address.objects.filter(user=user, is_deleted=False)
        # user.addresses.filter(is_deleted=False)
        address_list = []

        for address in addresses:
            address_data = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "province_id": address.province.id,
                "city": address.city.name,
                "city_id": address.city.id,
                "district": address.district.name,
                "district_id": address.district.id,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            address_list.append(address_data)

        # 处理 default_address 不存在的情况
        if user.default_address:
            default_address_id = user.default_address.id
        else:
            default_address_id = ''

        context = {
            "addresses": json.dumps(address_list),
            "default_address_id": default_address_id
        }

        # 4, 返回响应
        return render(request, 'user_center_site.html', context=context)
        pass


class AreasView(View):
    def get(self, request):
        # 返回区域数据
        # 1, 返回省份数据
        """
        {
          "code":"0",
          "errmsg":"OK",
          "province_list":[
              {
                  "id":110000,
                  "name":"北京市"
              },
              {
                  "id":120000,
                  "name":"天津市"
              },
              {
                  "id":130000,
                  "name":"河北省"
              },
              ......
          ]
        }

        """
        # 2, 返回城市或区县数据
        """
        {
          "code":"0",
          "errmsg":"OK",
          "sub_data":{
              "id":130000,
              "name":"河北省",
              "subs":[
                  {
                      "id":130100,
                      "name":"石家庄市"
                  },
                  ......
              ]
          }
        }
        """
        # 1, 接收数据
        area_id = request.GET.get('area_id')

        # 2, 校验数据

        # 3, 处理业务
        if not area_id:
            # 没有id, 就是取省份数据

            # 取缓存数据
            province_list = cache.get("province_list")

            if province_list:
                # 缓存中有数据
                res = {
                    'code': 0,
                    'errmsg': '成功',
                    'province_list': province_list
                }
                return JsonResponse(res)
            else:
                # 缓存中没数据
                province = Area.objects.filter(parent__isnull=True)
                province_list = []
                for p in province:
                    p_data = {
                        "id": p.id,
                        "name": p.name
                    }
                    province_list.append(p_data)

                # 把生成省份数据存入缓存
                cache.set("province_list", province_list, 3600 * 24 * 7)

                res = {
                    'code': 0,
                    'errmsg': '成功',
                    'province_list': province_list
                }
                return JsonResponse(res)
        else:
            # 取城市 区县数据
            area = Area.objects.get(id=area_id)  # 取到当前区域
            subs = area.subs.all()

            # 从缓存中取数据
            subs_list = cache.get("subs_list_%s" % area_id)

            if subs_list:
                # 如果缓存中有数据
                print('有缓存')
                res = {
                    'code': 0,
                    'errmsg': '成功',
                    'sub_data': {
                        "id": area.id,
                        "name": area.name,
                        "subs": subs_list
                    }
                }

                return JsonResponse(res)

            else:
                # 如果没有数据, 就生成数据, 并缓存起来
                print('没缓存')
                subs_list = []

                for sub in subs:
                    sub_data = {
                        "id": sub.id,
                        "name": sub.name
                    }
                    subs_list.append(sub_data)

                # 市,区数据存入缓存

                cache.set("subs_list_%s" % area_id, subs_list, 3600 * 24 * 7)

                res = {
                    'code': 0,
                    'errmsg': '成功',
                    'sub_data': {
                        "id": area.id,
                        "name": area.name,
                        "subs": subs_list
                    }
                }

                return JsonResponse(res)


class AddressesCreateView(LoginRequiredMixin, View):
    def post(self, request):
        # 新建收货地址
        # 1, 接收数据
        data = json.loads(request.body.decode())
        title = data.get('title')
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        # 2, 校验数据
        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 9999, 'errmsg': '信息不全'})

        # 2,1 校验省市区
        try:
            province = Area.objects.get(id=province_id)
            city = Area.objects.get(id=city_id)
            district = Area.objects.get(id=district_id)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 9999, 'errmsg': '区域数据有误'})

        # 2,2 校验手机号
        if not re.match(r'^1[3456789]\d{9}$', mobile):
            return JsonResponse({'code': 9999, 'errmsg': '手机格式不正确'})

        # 3, 处理业务
        # 保存收货地址
        user = request.user
        new_addr = Address.objects.create(
            user=user,
            title=title,
            receiver=receiver,
            province=province,
            city=city,
            district=district,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email,
        )
        address = {
            "id": new_addr.id,
            "title": new_addr.title,
            "receiver": new_addr.receiver,
            "province": new_addr.province.name,
            "province_id": new_addr.province.id,
            "city": new_addr.city.name,
            "city_id": new_addr.city.id,
            "district": new_addr.district.name,
            "district_id": new_addr.district.id,
            "place": new_addr.place,
            "mobile": new_addr.mobile,
            "tel": new_addr.tel,
            "email": new_addr.email
        }

        # 4, 返回响应
        res = {
            'code': 0,
            'errmsg': '成功',
            'address': address
        }
        return JsonResponse(res)

        pass


class AddressesDefaultView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        # 设置用户默认地址
        # 1, 接收数据
        user = request.user

        # 2, 校验数据
        pass

        # 3, 处理业务
        user.default_address_id = address_id
        user.save()

        # 4, 返回响应
        res = {
            'code': 0,
            'errmsge': '成功'
        }

        return JsonResponse(res)


class AddressUpdateView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        # 修改用户地址信息
        # 1, 接收数据
        data = json.loads(request.body.decode())
        title = data.get('title')
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        # 2, 校验数据
        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 9999, 'errmsg': '信息不全'})

        # 2,1 校验省市区
        try:
            province = Area.objects.get(id=province_id)
            city = Area.objects.get(id=city_id)
            district = Area.objects.get(id=district_id)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 9999, 'errmsg': '区域数据有误'})

        # 2,2 校验手机号
        if not re.match(r'^1[3456789]\d{9}$', mobile):
            return JsonResponse({'code': 9999, 'errmsg': '手机格式不正确'})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 9999, 'errmsg': '固定电话不正确'})

        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 9999, 'errmsg': '邮箱格式不正确'})
            pass

        # 2,4 校验地址id
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 9999, 'errmsg': '地址id不正确'})

        # 3, 处理业务

        # 3,2 更新地址
        address.title = title
        address.receiver = receiver
        address.province_id = province_id
        address.city_id = city_id
        address.district_id = district_id
        address.place = place
        address.mobile = mobile
        address.tel = tel
        address.email = email
        # 3,3 保存
        address.save()

        # 4, 返回响应
        address_data = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "province_id": address.province.id,
            "city": address.city.name,
            "city_id": address.city.id,
            "district": address.district.name,
            "district_id": address.district.id,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        res = {
            'code': 0,
            'errmsg': '成功',
            'address': address_data
        }
        return JsonResponse(res)

        pass
        pass

    def delete(self, request, address_id):
        # 设置地址删除标记, 逻辑删除一个地址
        # 1, 接收数据
        pass

        # 2, 校验数据
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return JsonResponse({"code": 9999, "errmsg": "地址id有误"})

        # 3, 处理业务
        address.is_deleted = True
        address.save()

        # 4, 返回响应
        res = {
            "code": 0,
            "errmsg": "成功"
        }
        return JsonResponse(res)

        pass


class AddressTitleView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        # 修改地址标题
        # 1, 接收数据
        data = json.loads(request.body.decode())
        title = data.get('title')

        # 2, 校验数据
        if not title:
            return JsonResponse({"code": 9999, "errmsg": '参数不全'})
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return JsonResponse({"code": 9999, "errmsg": '地址id不正确'})

        # 3, 处理业务
        address.title = title
        address.save()

        # 4, 返回响应
        res = {
            "code": 0,
            "errmsg": '成功'
        }

        return JsonResponse(res)
        pass


class PasswordChangeView(LoginRequiredMixin, View):
    def get(self, request):
        # 获取密码修改页面
        return render(request, 'user_center_pass.html')

    def post(self, request):
        # 设置密码
        # 1, 接收数据
        user = request.user
        old_password = request.POST.get('old_pwd')
        new_password = request.POST.get('new_pwd')
        new_password2 = request.POST.get('new_cpwd')

        # 2, 校验数据
        if not all([old_password, new_password, new_password2]):
            return HttpResponseForbidden('参数不全')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return HttpResponseForbidden('密码格式不正确')

        if new_password != new_password2:
            return HttpResponseForbidden('两次密码不一致')

        if user.check_password(raw_password=old_password):
            pass
        else:
            return HttpResponseForbidden('老密码不正确')

        # 3, 处理业务

        user.set_password(raw_password=new_password)
        user.save()

        # 登出
        logout(request)

        # 4, 返回响应
        response = redirect('/login/')
        response.delete_cookie('username')
        return response

        pass


class OrderInfoView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        # 展示用户订单页面
        # 1, 接收数据
        user = request.user

        # 2, 校验数据
        pass

        # 3, 处理业务
        # 获取订单信息,  订单商品信息
        order_all = user.orderinfo_set.all()
        per_page = 3
        p = Paginator(order_all, per_page)
        current_page = p.page(page_num)
        current_order_all = current_page.object_list

        order_list = []
        for order in current_order_all:
            # order = OrderInfo
            order_data = {
                'create_time': order.create_time.strftime('%Y-%m-%d %H:%M:%S'),
                'order_id': order.order_id,
                'total_amount': order.total_amount,
                'freight': order.freight,
                'status': order.status,
                'pay_method': order.pay_method,
                'sku_list': [],
                'comment_status': '已评价'
            }
            # 遍历订单商品
            goodssku_all = order.skus.all()
            for goodssku in goodssku_all:
                goodssku_data = {
                    'default_image_url': goodssku.sku.default_image_url.url,
                    'name': goodssku.sku.name,
                    'price': goodssku.price,
                    'count': goodssku.count,
                    'amount': goodssku.price * goodssku.count
                }

                if goodssku.is_commented:
                    pass
                else:
                    order_data['comment_status'] = '待评价'

                order_data['sku_list'].append(goodssku_data)

            order_list.append(order_data)

        # 4, 返回响应
        context = {
            'orders': order_list,
            'current_page': page_num,
            'total_pages': p.num_pages
        }
        return render(request, 'user_center_order.html', context=context)
        pass


class PasswordFindView(View):
    def get(self, request):
        return render(request, 'find_password.html')


class ChangePwdView(View):
    def post(self, request, user_id):
        data = request.body.decode()
        data_dict = json.loads(data)
        password = data_dict.get('password')
        password2 = data_dict.get('password2')
        access_token = data_dict.get('access_token')
        # 1.非空
        if not all([access_token, password, password2, ]):
            return http.HttpResponseForbidden('填写数据不完整')
        if password != password2:
            return http.HttpResponseForbidden('两个密码不一致')

        user_dict = meiduo_signature.loads(access_token, 300)
        if user_dict is None:
            return http.JsonResponse({}, status=400)

        if int(user_id) != user_dict['user_id']:
            return http.JsonResponse({}, status=400)

        try:
            user = User.objects.get(id=user_id)
        except:
            return http.JsonResponse({}, status=400)

        user.set_password(password)
        user.save()
        return http.JsonResponse({})
